// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.statement.SQLTableSource;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
// import com.alibaba.druid.sql.parser.Lexer;
// import com.alibaba.druid.sql.parser.ParserException;
// import com.alibaba.druid.sql.parser.SQLStatementParser;
// import com.alibaba.druid.sql.parser.Token;

#include "OracleUpdateParser.h"
#include "../../../parser/Token.h"
#include "../../../parser/ParserException.h"
#include "../../../parser/Lexer.h"
#include "../../../parser/SQLSelectParser.h"
#include "../ast/stmt/OracleUpdateStatement.h"
#include "../../../ast/statement/SQLTableSource.h"
#include "../../../ast/SQLExpr.h"
#include "OracleExprParser.h"

OracleUpdateParser::OracleUpdateParser(string_ptr sql)
    : SQLStatementParser(OracleExprParser_ptr(new OracleExprParser(sql)))
{
}

OracleUpdateParser::OracleUpdateParser(Lexer_ptr lexer)
    : SQLStatementParser(OracleExprParser_ptr(new OracleExprParser(lexer)))
{
}

SQLUpdateStatement_ptr OracleUpdateParser::parseUpdateStatement()
{
  OracleUpdateStatement_ptr update = OracleUpdateStatement_ptr(new OracleUpdateStatement());

  if (lexer->token()->name->c_str() == Token::UPDATE.name->c_str())
  {
    lexer->nextToken();

    parseHints(update);

    if (lexer->identifierEquals(make_string_ptr("ONLY")))
    {
      update->setOnly(BOOL::TRUE);
    }

    SQLTableSource_ptr tableSource = this->exprParser->createSelectParser()->parseTableSource();
    update->setTableSource(tableSource);

    if ((update->getAlias() == nullptr) || (update->getAlias()->length() == 0))
    {
      update->setAlias(tableAlias());
    }
  }

  parseUpdateSet(update);

  parseWhere(update);

  parseReturn(update);

  parseErrorLoging(update);

  return update;
}

void OracleUpdateParser::parseErrorLoging(OracleUpdateStatement_ptr update)
{
  if (lexer->identifierEquals(make_string_ptr("LOG")))
  {
    std::string tmp = "TODO. ";
    tmp += encode_util::UnicodeToUTF8(lexer->info());
    throw new ParserException(make_string_ptr(tmp));
  }
}

void OracleUpdateParser::parseReturn(OracleUpdateStatement_ptr update)
{
  if (lexer->token()->name->c_str() == Token::RETURN.name->c_str() ||
      lexer->token()->name->c_str() == Token::RETURNING.name->c_str())
  {
    lexer->nextToken();

    for (;;)
    {
      SQLExpr_ptr item = this->exprParser->expr();
      update->getReturning()->push_back(item);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }

    accept(Token::INTO);

    for (;;)
    {
      SQLExpr_ptr item = this->exprParser->expr();
      update->addReturningInto(item);

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }
  }
}

void OracleUpdateParser::parseHints(OracleUpdateStatement_ptr update)
{
  this->exprParser->parseHints(update->getHints());
}

void OracleUpdateParser::parseWhere(OracleUpdateStatement_ptr update)
{
  if (lexer->token()->name->c_str() == (Token::WHERE.name->c_str()))
  {
    lexer->nextToken();
    update->setWhere(this->exprParser->expr());
  }
}
